#include "./CQSlotCore/CQ_includes.h"

#include <stdlib.h>
using namespace CQSLOT;

class ThreadTest : public CQSLOT::CQThread
{
public:
	CQ_SIGNAL(int, int) signalObj;

	bool threadRun()
	{
		CQ_EMIT(signalObj, rand() % 100, rand() % 100);
		std::this_thread::sleep_for(std::chrono::milliseconds((rand() % 10) * 1000));
		return true;
	}
};

class Test1 : public CQSLOT::CQObject
{
public:
	void add(int a, int b)
	{
		CQ_DEBUG_LOG(a, '+', b, '=', a + b);
	}

	void timeOut()
	{
		CQ_DEBUG_LOG("time out");
	}
};

class Test2 : public CQSLOT::CQObject
{
public:
	void reduce(int a, int b)
	{
		CQ_DEBUG_LOG(a, '-', b, '=', a - b);
	}

	void timeOut()
	{
		CQ_DEBUG_LOG("time out");
	}
};


//根据运行结果：1、某对象如果被移交给了独立线程，则该对象成员函数都在独立线程上跑；否则就在主线程上跑。2、槽函数所在线程与对应信号所在的线程无关。
int main()
{
    // 定义一个独立的线程对象，后面可能用得上
    CQSLOT::CQThread th;
    // 定义完就启动
    th.start();
    std::cout << "任务线程: " << th.getId() << "\n主线程: " << std::this_thread::get_id() << std::endl;

    // 测试类1，我们让它跑在独立线程上
    Test1 test1;
    // 这里意思是我希望目标对象的所有函数在独立线程中跑，而不是在主线程中执行
    test1.moveToThread(&th);

    // 测试类2，我们让它直接在主线程上跑
    Test2 test2;

    // 演示1，定义一个线程信号类，其实不定义也可以，为了演示而已，直接用CQ_EMIT发射信号也可
    ThreadTest tt;
    //把一个信号对象（用CQ_SIGNAL进行定义）绑定到目标槽函数，可以绑n个，它们是“m -- n”的对应关系，非常灵活
    CQ_CONNECT(tt.signalObj, &test1, &Test1::add);
    CQ_CONNECT(tt.signalObj, &test2, &Test2::reduce);
    // 启动线程，这个线程内部会立即发射信号，信号会立即触发上面connect连接的槽函数
    tt.start(SINGLE); //SINGLE参数表示只执行一次线程循环，不要该参数则默认循环
    std::cout << "信号线程: " << tt.getId() << std::endl;

    // 演示2，定义一个定时器类，定时器定时结束就会发射信号
    CQSLOT::CQTimer timer;
    // 把定时器“定时结束”的信号绑定后面的函数，跟上面一样，“m -- n”的对应关系
    CQ_CONNECT(timer.timeout, &test1, &Test1::timeOut);
    CQ_CONNECT(timer.timeout, &test2, &Test2::timeOut);
    // 定时器开始计时
    timer.start(1000, SINGLE);//SINGLE参数表示只执行一次定时器倒计时，不要该参数则默认循环

    // 开启事件循环
    return CQ_EXEC();
}
